import base64
import io
import threading

from Crypto.Cipher import AES


class Crypt:
    """
    加密解密类，传入16位随机bytes以base64编码的key
    """
    _lock = threading.Lock()

    def __init__(self, key: str):
        self.mode = AES.MODE_GCM
        self.key = base64.b64decode(key)

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            with cls._lock:
                if not hasattr(cls, '_instance'):
                    cls._instance = super().__new__(cls)
        return cls._instance

    def encrypt(self, value: str):
        cipher = AES.new(self.key, self.mode)
        ciphertext, tag = cipher.encrypt_and_digest(value.encode('utf8'))
        c = base64.b64encode(cipher.nonce + tag + ciphertext)
        return c.decode('utf8')

    def decrypt(self, text: str):
        data = base64.b64decode(text.encode('utf8'))
        b = io.BytesIO(data)
        nonce, tag, ciphertext = [b.read(x) for x in (16, 16, -1)]
        cipher = AES.new(self.key, self.mode, nonce)
        text = cipher.decrypt_and_verify(ciphertext, tag)
        return text.decode('utf8')
